//----------------------------------Include-------------------------------------
#include "mcu.h"
//------------------------------------------------------------------------------

//主存储区
//页名称     地址范围                   大小
//页 0       0x0800_0000 – 0x0800_01FF  0.5KB
//页 1       0x0800_0200 – 0x0800_03FF  0.5KB
//页 2       0x0800_0400 – 0x0800_05FF  0.5KB
//...        
//页 126     0x0800_FC00 – 0x0800_FDFF  0.5KB
//页 127     0x0800_FE00 – 0x0800_FFFF  0.5KB

//信息区
//系统存储区 0x1FFF_0000 – 0x1FFF_0BFF    3KB
//系统配置区 0x1FFF_F000 – 0x1FFF_F5FF  1.5KB
//选项字节区 0x1FFF_F600 – 0x1FFF_F60D    14B


//total:       64KB
//page:        128
//page size:   512B
//addr:        0x0800_0000 - 0x0800_FFFF

//-----------------------------------Macro--------------------------------------
#define _PAGE_BYTES          512
//------------------------------------------------------------------------------

//--------------------------------Static Func-----------------------------------
static void _RdNByte_InOnePage(uint32_t addr, uint8_t* pdata, uint32_t N)
{ 
  uint32_t  i;
  
  for(i=0; i<N; i++){
    pdata[i] = (*(volatile uint8_t*)(addr + i));
  }
}

static void _WrNByte_InOnePage(uint32_t addr, uint8_t* pdata, uint32_t N)
{ 
  uint32_t  i;
  
#if 1
  static uint8_t  rd_buf[_PAGE_BYTES];
  _RdNByte_InOnePage(addr, rd_buf, N);
  for(i=0; i<N; i++){
    if(rd_buf[i] != pdata[i]) break;
  }
  if(i>=N) return;    //same
#endif
  
  uint32_t  pg_start, buf_start;
  
  pg_start  = addr/_PAGE_BYTES*_PAGE_BYTES;
  buf_start = addr%_PAGE_BYTES;
  
  FLASH_Unlock();
  _RdNByte_InOnePage(pg_start, rd_buf, _PAGE_BYTES);  //read one page
  FLASH_EraseOnePage(addr);
  for(i=0; i<N; i++){
    rd_buf[buf_start +i] = pdata[i];
  }
  for(i=0; i<_PAGE_BYTES; i+=4){
    FLASH_ProgramWord(pg_start +i, *(uint32_t*)&rd_buf[i]);
  }
  FLASH_Lock();
}
//------------------------------------------------------------------------------

//--------------------------------Public Func-----------------------------------
void mcu_flash_wr_n_byte(uint32_t addr, uint8_t* pdata, uint32_t len)
{ 
  uint32_t   Temp,NTail,NHead,Page;
  uint8_t*   p;
  
  Temp  = (addr + _PAGE_BYTES)/_PAGE_BYTES*_PAGE_BYTES;
  NHead = Temp - addr;
  if(NHead >= len){
    NHead = len;
    NTail = 0;
    Page = 0;
  }else{
    NTail = (addr+len)-((addr+len)/_PAGE_BYTES*_PAGE_BYTES);
    Page = (len-NHead-NTail)/_PAGE_BYTES;
  }
  p = pdata;
  Temp = addr;
  if(NHead){
    _WrNByte_InOnePage(Temp, p, NHead);
    p += NHead;
    Temp += NHead;
  }
  while(Page){
    _WrNByte_InOnePage(Temp, p, _PAGE_BYTES);
    Page--;
    p += _PAGE_BYTES;
    Temp += _PAGE_BYTES;
  }
  if(NTail){
    _WrNByte_InOnePage(Temp, p, NTail);
  }
}

void mcu_flash_rd_n_byte(uint32_t addr, uint8_t* pdata, uint32_t len)
{
  uint32_t   Temp,NTail,NHead,Page;
  uint8_t*   p;
  
  Temp  = (addr + _PAGE_BYTES)/_PAGE_BYTES*_PAGE_BYTES;
  NHead = Temp - addr;
  if(NHead >= len){
    NHead = len;
    NTail = 0;
    Page = 0;
  }else{
    NTail = (addr+len)-((addr+len)/_PAGE_BYTES*_PAGE_BYTES);
    Page = (len-NHead-NTail)/_PAGE_BYTES;
  }
  p = pdata;
  Temp = addr;
  if(NHead){
    _RdNByte_InOnePage(Temp, p, NHead);
    p += NHead;
    Temp += NHead;
  }
  while(Page){
    _RdNByte_InOnePage(Temp, p, _PAGE_BYTES);
    Page--;
    p += _PAGE_BYTES;
    Temp += _PAGE_BYTES;
  }
  if(NTail){
    _RdNByte_InOnePage(Temp, p, NTail);
  }
}
//------------------------------------EOF---------------------------------------









